package com.ponhu.ea2.stockcenter.provider.service.biz.stockwarehouse;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.ponhu.ea2.stockcenter.dto.WMSEventInfoDTO;
import com.ponhu.ea2.stockcenter.enums.ExchangeActionTypeEnum;
import com.ponhu.ea2.stockcenter.provider.entity.StockInventoryDocOccupy;
import com.ponhu.ea2.stockcenter.provider.support.exception.StockRuntimeException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

import static com.ponhu.ea2.stockcenter.enums.ResponseCodeEnum.STOCK_SALES_EXCEPTION_900301;
import static com.ponhu.ea2.stockcenter.enums.ResponseCodeEnum.STOCK_WAREHOUSE_EXCEPTION_900115;

/**
 * 调拨申请
 */
@Component
public class TransferApplyHandler extends AbsCoreHandler {

    public TransferApplyHandler() {
        inOccupy = false;
        operateWarehouse = false; // 当前操作仓库是 outWarehouse
        whActionTypeArr = new ExchangeActionTypeEnum[]{
                ExchangeActionTypeEnum.TRANSFER_APPLY
        };
    }

    // 可售仓主仓库(二奢仓或标品仓)
    @Value("${warehouse.main}")
    private String warehouseMain;

    @Override
    protected void absHandle(WMSEventInfoDTO eventInfoDTO) {

        // 校验调拨申请货品库存数
        transferApplyCheck(eventInfoDTO);

        // 仓库库存变动数据库操作
        stockWarehouseHandle(eventInfoDTO);

        // 仓库库存变动对销售库存影响
        salesStockHandle(eventInfoDTO);

        // 调拨申请特有处理逻辑
        transferApplyHandle(eventInfoDTO);
    }

    /**
     * 调拨申请库存校验
     */
    private void transferApplyCheck(WMSEventInfoDTO eventInfoDTO) {

        // 申请调拨的货品在当前仓库不存在
        absUtilHandler.hasOperateInventory(eventInfoDTO);

        // 可售仓之间的调拨申请校验
        if (eventInfoDTO.getOutWarehouseIsSale() && eventInfoDTO.getInWarehouseIsSale()) {
            // 调拨申请调出仓是主仓库(比如二奢仓)
            if (Arrays.asList(warehouseMain.split(",")).contains(eventInfoDTO.getOutWarehouseCode())) {
                // 严格校验，如同 可售仓到不可售仓的调拨申请校验
                applySaleToNoSaleCheck(eventInfoDTO);
            } else { // 调拨申请调出仓不是主仓库(比如二奢仓)
                isSaleOccupyLocal.set(true);
                applyCommonCheck(eventInfoDTO);
            }
            return; // 命中校验场景并完成检验后返回
        }

        // 可售仓到不可售仓的调拨申请校验
        if (eventInfoDTO.getOutWarehouseIsSale() && !eventInfoDTO.getInWarehouseIsSale()) {
            applySaleToNoSaleCheck(eventInfoDTO);
            return; // 命中校验场景并完成检验后返回
        }

        // 通用调拨申请库存校验(不可售仓到可售仓、不可售仓之间)
        applyCommonCheck(eventInfoDTO);
    }

    /**
     * 可售仓到不可售仓的调拨申请校验
     */
    private void applySaleToNoSaleCheck(WMSEventInfoDTO eventInfoDTO) {

        // 有业务单号(链路单号)：实物可用库存 >= 调拨库存 && 销售占用 >= 调拨库存
        // 无业务单号(链路单号)：实物可用库存 - 全部链路占用 >= 调拨库存 &&
        //                                       销售占用(货品总可售仓库数 - 货品总销售占用) >= 调拨库存
        absAssistHandler.commonSaleOutStockCheck(eventInfoDTO, operateWarehouse);
    }

    /**
     * 通用调拨申请库存校验
     * --- 可售仓之间(调出仓非主仓库)
     * --- 不可售仓到可售仓
     * --- 不可售仓之间
     */
    private void applyCommonCheck(WMSEventInfoDTO eventInfoDTO) {

        // 不可售仓到可售仓的调拨申请若是订单履约和采退履约则抛出违规异常
        if (!eventInfoDTO.getOutWarehouseIsSale() && eventInfoDTO.getInWarehouseIsSale()) {
            List<StockInventoryDocOccupy> occupyList = stockInventoryDocOccupyService
                    .getPlacedAndNoOccupyAndTransferAppliedAndOutedDocRecord(eventInfoDTO.getDocNo());
            if (CollectionUtils.isNotEmpty(occupyList)) {
                throw new StockRuntimeException(STOCK_WAREHOUSE_EXCEPTION_900115);
            }
        }

        // 有业务单号(链路单号)：实物可用库存 - 全部链路占用 >= 调拨库存
        // 无业务单号(链路单号)：实物可用库存 >= 调拨库存
        absAssistHandler.commonNoSaleOutStockCheck(eventInfoDTO, operateWarehouse);
    }

    /**
     * 调拨申请特有处理逻辑
     */
    private void transferApplyHandle(WMSEventInfoDTO eventInfoDTO) {

        // 判断调拨申请是否发生在 可售仓 到 不可售仓
        if (!(eventInfoDTO.getOutWarehouseIsSale() && !eventInfoDTO.getInWarehouseIsSale())) {
            return;
        }

        // 根据是否有关联单据号判断是否需要调用销售层方法
        if (StringUtils.isNotBlank(eventInfoDTO.getDocNo())) {

            // 查询关联单据号是否存在销售侧库存占用
            List<StockInventoryDocOccupy> docOccupyList = stockInventoryDocOccupyService
                    .getDocOccupyRecord(eventInfoDTO.getDocNo());
            if (CollectionUtils.isEmpty(docOccupyList)) {
                return; // 不存在销售侧库存占用
            }

            // 释放货品销售侧或库存占用
            if (!stockInventoryDocOccupyService.releaseDocOccupy(
                    eventInfoDTO.getDocNo(), eventInfoDTO.getActionType(), saleEventLocal.get())) {
                throw new StockRuntimeException(STOCK_SALES_EXCEPTION_900301);
            }
        }
    }

}
